11724. Infected tree

 

You are given a binary tree, which is an acyclic connected undirected graph containing n vertices and n – 1 edges. Each vertex has a degree of no more than 3. The root is the vertex number 1, with its degree not exceeding 2.

Unfortunately, the root of the tree is infected. The following process is repeated n times:

·        Huseyn either selects a vertex that is not yet infected (and not yet removed) and removes it along with all its incident edges, or he takes no action.

·        After that, the infection spreads to every vertex connected by an edge to an already infected vertex (all previously infected vertices remain infected).

Help Huseyn determine the maximum number of vertices he can save from infection (note that removed vertices are not considered saved).

 

Input. The first line contains the number of vertices in the tree n (2 ≤ n ≤ 3 * 105).

Each of the following n – 1 lines contains two integers ui and vi (1 ≤ ui, vi n), representing an edge of the tree.

It is guaranteed that the graph is a binary tree with the root at vertex 1.

 

Output. Print a single integer – the number of saved vertices.

 

Sample input 1

Sample output 1

4

1 2

2 3

2 4

2

 

 

Sample input 2

Sample output 2

7

1 2

1 5

2 3

2 4

5 6

5 7

2

 

 

SOLUTION

treedynamic programming

 

Algorithm analysis

For each vertex v, compute the number of vertices sum[v] in the subtree where it is the root. If to1, to2, …, tok are the children of vertex v, then

sum[v] = 1 + sum[to1] + sum[to2] + … + sum[tok]

If vertex v is a leaf of the tree, then sum[v] = 1.

 

Let dp[v] be the number of saved vertices in the subtree with root v, assuming that currently vertex v (and only it in the subtree) is infected.

If vertex v has only one child to, then dp[v] = sum[to] – 1 (the removed vertex to is not considered saved).

Let vertex v have two children to1 and to2 (each vertex has a degree of at most 3). Then we have two options:

·        Remove to1 and recursively save the vertices in the subtree with root to2. The number of saved vertices will be sum[to1] – 1 + dp[to2].

·        Remove to2 and recursively save the vertices in the subtree with root to1. The number of saved vertices will be sum[to2] – 1 + dp[to1].

Among the two options, choose the one that maximizes the number of saved vertices.

 

Consider the depth-first search process when examining the edge (v, to).

Let a be the second child of vertex v. We need to compute the value dp[to] + sum[a] – 1. Let’s try to find it using only the vertices v and to. We know that:

sum[v] = 1 + sum[to] + sum[a]

From which it follows that:

sum[a] = sum[v]sum[to] – 1

Thus,

dp[to] + sum[a] – 1 = dp[to] + sum[v]sum[to] – 2

Iterate over the children to of the vertex v and compute:

dp[v] = max(dp[to] + sum[v]sum[to] – 2)

 

Example

In the first example, Huseyn is able to save two vertices, 3 and 4, by choosing vertex number 2 as his first move.

Consider the second example. Next to each vertex v, place the labels sum[v] / dp[v]. The vertices chosen by Huseyn are displayed in green.

For example,

dp[1] = max(sum[2] – 1 + dp[5], sum[5] – 1 + dp[2]) = max(2, 2) = 2,

sum[1] = 1 + sum[2] + sum[5] = 1 + 3 + 3 = 7

 

Algorithm implementation

Declare the arrays.

 

#define MAX 300005

int sum[MAX], dp[MAX];

vector<vector<int>> g;

 

The function dfs performs a depth-first search starting from vertex v. The parent of vertex v is p.

 

void dfs(int v, int p = -1)

{

 

Initialize the variables sum[v] and dp[v].

 

  sum[v] = 1;

  dp[v] = 0;

 

Perform a depth-first search starting from the children of vertex v.

 

  for (int to : g[v])

    if (to != p)

    {

      dfs(to, v);

      sum[v] += sum[to];

    }

 

Compute the value of dp[v].

 

  for (int to : g[v])

    if (to != p)

    {

      dp[v] = max(dp[v], sum[to] - 1); // if 1 son

      dp[v] = max(dp[v], dp[to] + sum[v] - sum[to] - 2);

    }

}

 

The main part of the program. Read the input data.

 

scanf("%d", &n);

g.clear(); g.resize(n + 1);

memset(dp, 0, sizeof(dp));

memset(sum, 0, sizeof(sum));

for (i = 1; i < n; i++)

{

  scanf("%d %d", &u, &v);

  g[u].push_back(v);

  g[v].push_back(u);

}

 

Perform a depth-first search starting from vertex 1.

 

dfs(1);

 

Print the answer.

 

printf("%d\n", dp[1]);